package com.navinfo.data.journal;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.*;

/**
 * 车辆趟程发现，及其平均运程计算
 */
//TODO:由于采用有向邻接矩阵计算，计算出的趟程及其运程/时长可能不准确，新启V2版本通过回查行程数据精华数据准确性
public class VehicleJournalV2 {
    private static final Logger LOGGER = LoggerFactory.getLogger(VehicleJournalV2.class);

    /**
     * 运距(米)
     */
    private static int LOAD_DISTANCE = 10*1000;
    /**
     * JournalVertex集合
     */
    private static List<JournalVertex> jvs = new ArrayList<JournalVertex>();
    /**
     * JournalEdge集合
     */
    private static Map<String,JournalEdge> jes = new HashMap<String,JournalEdge>();

    /**
     * add or find SimilarVertex
     * 找到list中点距小于LOAD_DISTANCE的点
     * 如果找不到，则添加新点
     *
     * @param lat2 经度
     * @param lng2 维度
     * @param time 时间点
     * @param flag 0开始时间点，1结束时间点
     * @return list下标
     */
    private static int afSimilarVertex(double lat2, double lng2, int time,int flag) {
        int result = -1;
        for(int i = 0 ; i < jvs.size() ; i++) {
            JournalVertex jv = jvs.get(i);
            double lat1 = jv.getLat();
            double lng1 = jv.getLng();
            if (LocationUtils.getDistance(lat1, lng1, lat2, lng2)<=LOAD_DISTANCE) {
                jv.getTimelist().add(time+":"+flag);
                jvs.set(i,jv);
                result = i;
                break;
            }
        }
        if (result==-1) {
            JournalVertex jv =new JournalVertex(lat2,lng2);
            jv.getTimelist().add(time+":"+flag);
            jvs.add(jv);
            result = jvs.size()-1;
        }

        return result;
    }

    /**
     * 通过HashSet踢除重复元素
     * @param list
     * @return
     */
    public static List removeDuplicate(List list) {
        HashSet h = new HashSet(list);
        list.clear();
        list.addAll(h);
        return list;
    }

    /**
     * add or update JournalEdge
     */
    private static void afJournalEdge(long src, long dst, int totalDistance, int routeStartTime, int routeEndTime,int vehicleEstimatedLoad) {
        String mapkey = src + "-" + dst;
        if (jes.containsKey(mapkey)) {
            JournalEdge je = jes.get(mapkey);
            je.setTimes(je.getTimes() + 1);
            je.setTotalDistance(je.getTotalDistance() + totalDistance);
            je.setTotalVehicleEstimatedLoad(je.getTotalVehicleEstimatedLoad()+vehicleEstimatedLoad);
            je.setTotalDuration(je.getTotalDuration() + (routeEndTime - routeStartTime));
            jes.put(mapkey, je);
        } else {
            JournalEdge je = new JournalEdge(src, dst, totalDistance, 1, routeEndTime - routeStartTime,vehicleEstimatedLoad);
            jes.put(mapkey, je);
        }
    }

    /**
     * 计算运程和时长
     *
     * @param res 某个趟程点列表字符串
     * @param tripRecordList 行程列表
     * @return 运程:合计里程:平均时长
     */
    private static String computeDistanceDuration(String res,List<TripRecord> tripRecordList) {
        String cdd_result = "";
        String[] points = res.split(":")[1].split("---");

        Iterator tit = tripRecordList.iterator();
        int tc_start_node = Integer.parseInt(points[0]);
        int tc_current_node = tc_start_node;
        int tc_i = 1;//points指针
        int times = 0;//次数
        int totalDistance = 0;//本趟程所有里程
        int totalDuration = 0;//本趟程所有时长
        Boolean tcFlag = false;//趟程标志
        while(tit.hasNext()) {
            TripRecord tr = (TripRecord) tit.next();

            if (!tcFlag) {
                if (tr.getSrc()==tc_start_node) {
                    tcFlag = true;
                    continue;
                }
            }
            if (tcFlag) {
                if (tc_i<points.length) {
                    tc_i++;
                    tc_current_node = Integer.parseInt(points[tc_i-1]);
                    if (tr.getSrc()==tc_current_node) {
                        totalDistance = totalDistance + tr.getRouteIntegralMileage();
                        totalDuration = totalDuration + (tr.getRouteEndTime()-tr.getRouteStartTime());
                        if (tr.getSrc()==tc_start_node) {
                            times++;
                            tcFlag = false;
                            tc_i = 1;
                        }
                        continue;
                    } else {
                        break;
                    }
                } else {
                    break;
                }
            }
        }
        //运程:合计里程:平均时长
        if (times != 0) {
            int journalDistance = totalDistance/times;
            int avgDuration = totalDuration/times;
            cdd_result = journalDistance+":"+totalDistance+":"+avgDuration;
        } else {
            cdd_result = "0:0:0";
        }

        return cdd_result;
    }


    public static void main(String[] args) {
        Reader in = null;
        try {
            //百事车辆
//            in = new FileReader("E:\\qingqidata\\10019411330\\10019411330驾驶行为分析(2018-11-07-00-00-00至2018-11-12-00-00-00).csv");
            //节油大赛车辆
//            in = new FileReader("E:\\qingqidata\\10021042261驾驶行为分析(2018-09-27-00-00-00至2018-09-29-00-00-00).csv");
            //随便找的一台车
//            in = new FileReader("E:\\qingqidata\\10020435809驾驶行为分析(2018-12-10-00-00-00至2018-12-12-00-00-00).csv");
            //随便找的一台of37车
//            in = new FileReader("E:\\qingqidata\\10019410082驾驶行为分析(2018-12-10-00-00-00至2018-12-12-00-00-00).csv");
            //随便找的一台of37车（14天发现闭环）
            in = new FileReader("E:\\qingqidata\\14705564807\\14705564807驾驶行为分析(2018-12-04-00-00-00至2018-12-18-00-00-00).csv");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            LOGGER.error("FileNotFoundException");
        }
        Iterable<CSVRecord> records = null;
        try {
            records = CSVFormat.RFC4180.withFirstRecordAsHeader().parse(in);
        } catch (IOException e) {
            e.printStackTrace();
            LOGGER.error("IOException");
        }

        DsfCycle dc = new DsfCycle();

        //行程records需要按照行程时间排序！！！！！！！！！！！！！！！！！！！
        List<TripRecord> tripRecordList = new ArrayList<TripRecord>();
        for (CSVRecord record : records) {
            double routeStartLatitude =  Double.parseDouble(record.get("routeStartLatitude"))/1000000;
            double routeStartLongitude =  Double.parseDouble(record.get("routeStartLongitude"))/1000000;
            double routeEndLatitude =  Double.parseDouble(record.get("routeEndLatitude"))/1000000;
            double routeEndLongitude =  Double.parseDouble(record.get("routeEndLongitude"))/1000000;
            int routeIntegralMileage =  Integer.parseInt(record.get("routeIntegralMileage"));
            int routeStartTime =  Integer.parseInt(record.get("routeStartTime"));
            int routeEndTime =  Integer.parseInt(record.get("routeEndTime"));
            int vehicleEstimatedLoad = Integer.parseInt(record.get("vehicleEstimatedLoad"));

            int src = afSimilarVertex(routeStartLatitude,routeStartLongitude,routeStartTime,0);
            int dst = afSimilarVertex(routeEndLatitude,routeEndLongitude,routeEndTime,1);
            afJournalEdge(src, dst, routeIntegralMileage, routeStartTime, routeEndTime,vehicleEstimatedLoad);
            dc.addLine(String.valueOf(src),String.valueOf(dst));

            tripRecordList.add(new TripRecord(src,dst,routeIntegralMileage,routeStartTime,routeEndTime));
        }

        LOGGER.info("-----------打印所有趟程停靠点--------------");
        int num = 0;
        for(JournalVertex attribute : jvs) {
            LOGGER.info("Number:"+num+", "+attribute.toString());
            num++;
        }

        //获取有向图闭环
        List<String> reslut_src = removeDuplicate(dc.find());
//        reslut_src = new ArrayList<String>();
//        reslut_src.add("cycle:35---34---35");
//        for (String res : reslut_src) {
//            System.out.println(res);
//        }

        List<String> reslut_dst = new ArrayList<String>();
        //读取文件中所有行程的里程
        int allTotalDistance = 0;

        for (String res : reslut_src) {
            if ("no_cycle".equals(res)) {
                break;
            }
            String cdd_result = computeDistanceDuration(res,tripRecordList);

            //cycle:0---2---3---0:318759:468474:50000
            //cycle:点序列:运程:合计里程:平均时长
//            reslut_dst.add(res+":"+journalDistance+":"+totalDistance+":"+avgDuration);
            reslut_dst.add(res+":"+cdd_result);
            allTotalDistance = allTotalDistance + Integer.parseInt(cdd_result.split(":")[1]);
        }
//        LOGGER.info("allTotalDistance="+allTotalDistance);

        List<JournalDesc> jds = new ArrayList<JournalDesc>();
        for (String res : reslut_dst) {
            String[] desc = res.split(":");
            jds.add(new JournalDesc(desc[1],Integer.parseInt(desc[2]),Integer.parseInt(desc[3]),Integer.parseInt(desc[4])));
        }
        jds.sort(Comparator.comparingInt(JournalDesc::getTotalDistance));

        LOGGER.info("-----------打印所有趟程描述--------------");
        for (JournalDesc res : jds) {
            LOGGER.info(res.toString());
        }

        LOGGER.info("-----------输出该车辆的总体平均运程和时长--------------");
        double avgJournalDistance = 0;
        for (JournalDesc res : jds) {
            avgJournalDistance = avgJournalDistance + res.getJournalDistance()*( (double) res.getTotalDistance()/allTotalDistance);
        }
        LOGGER.info("avgJournalDistance="+(int)avgJournalDistance);
        double avgJournalDuration = 0;
        for (JournalDesc res : jds) {
            avgJournalDuration = avgJournalDuration + res.getAvgDuration()*( (double) res.getTotalDistance()/allTotalDistance);
        }
        LOGGER.info("avgJournalDuration="+(int)avgJournalDuration);


    }
}